package com.future.service.Impl;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.future.WebSocket.WebSocketSessionManager;
import com.future.allUtils.constants.RedisCacheConstants;
import com.future.allUtils.enums.TargetTypeEnum;
import com.future.allUtils.utils.SecurityUtils;
import com.future.domain.*;
import com.future.domain.DTO.NotificationDTO;
import com.future.domain.DTO.PageDTO;
import com.future.mapper.ChatRoomMemberMapper;
import com.future.mapper.NotificationMapper;
import com.future.mapper.UserMapper;
import com.future.service.NotificationService;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.lang.annotation.Target;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class NotificationServiceImpl implements NotificationService {
    @Autowired
    private WebSocketSessionManager webSocketSessionManager;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private NotificationMapper notificationMapper;
    @Autowired
    private ChatRoomMemberMapper roomMemberMapper;

    //发送消息
    private <T> void sendMessage(Long receiverId, T message) {
        WebSocketSession session = webSocketSessionManager.getSession(receiverId);
        try {
            String s = objectMapper.writeValueAsString(message);
            session.sendMessage(new TextMessage(s));
        } catch (Exception e) {
            log.error("消息处理失败" + e);
        }
    }

    @Override
    public void sendLike(Long receiverId, Long relatedId, String content) {
        try {
            Long currentId = SecurityUtils.getCurrentUserId();
            //默认未读
            Notification notification = new Notification(null, receiverId, content, "点赞", relatedId, 0, new Date(), currentId);
            WebSocketSession session = webSocketSessionManager.getSession(receiverId);

            //存入数据库
            notificationMapper.insert(notification);

            //更新redis中的未读消息数
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + notification.getNotificationType() + ":" + receiverId;
            stringRedisTemplate.opsForValue().increment(unReadKey);
            stringRedisTemplate.expire(unReadKey, 1, TimeUnit.HOURS);
            //消息存入redis
            NotificationDTO notificationDTO1 = notificationMapper.selectLikeNotificationDtoById(notification.getId());
            String unread = stringRedisTemplate.opsForValue().get(unReadKey);
            notificationDTO1.setUnreadCount(unread == null ? 0 : Integer.parseInt(unread));
            String notificatioKey = RedisCacheConstants.NOTIFICATION_MESSAGE + notification.getNotificationType() + ":" + notification.getUserId();
            String jsonStr = objectMapper.writeValueAsString(notificationDTO1);
            stringRedisTemplate.opsForZSet().add(notificatioKey, jsonStr, notification.getCreatedAt().getTime());
            //设置过期时间
            stringRedisTemplate.expire(notificatioKey, 7, TimeUnit.DAYS);

            //在线就发送
            if (session != null && session.isOpen()) {
                sendMessage(receiverId, notificationDTO1);
            } else {
                //处理离线消息
                handleOfflineMessage(notificationDTO1);
            }
        } catch (Exception e) {
            log.error("发送消息失败", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendMark(Long receiverId, Long relatedId, String content) {
        try {
            Long currentId = SecurityUtils.getCurrentUserId();
            //默认未读
            Notification notification = new Notification(null, receiverId, content, "收藏", relatedId, 0, new Date(), currentId);
            WebSocketSession session = webSocketSessionManager.getSession(receiverId);

            //存入数据库
            notificationMapper.insert(notification);

            //更新redis中的未读消息数
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + notification.getNotificationType() + ":" + receiverId;
            stringRedisTemplate.opsForValue().increment(unReadKey);
            stringRedisTemplate.expire(unReadKey, 1, TimeUnit.HOURS);
            //消息存入redis
            NotificationDTO notificationDTO1 = notificationMapper.selectMarkNotificationDTOById(notification.getId());
            String unread = stringRedisTemplate.opsForValue().get(unReadKey);
            notificationDTO1.setUnreadCount(unread == null ? 0 : Integer.parseInt(unread));
            String notificatioKey = RedisCacheConstants.NOTIFICATION_MESSAGE + notification.getNotificationType() + ":" + notification.getUserId();
            String jsonStr = objectMapper.writeValueAsString(notificationDTO1);
            stringRedisTemplate.opsForZSet().add(notificatioKey, jsonStr, notification.getCreatedAt().getTime());
            //设置过期时间
            stringRedisTemplate.expire(notificatioKey, 7, TimeUnit.DAYS);

            //在线就发送
            if (session != null && session.isOpen()) {
                sendMessage(receiverId, notificationDTO1);
            } else {
                //处理离线消息
                handleOfflineMessage(notificationDTO1);
            }
        } catch (Exception e) {
            log.error("发送消息失败", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendComment(Integer targetTypeId, Long receiverId, Long relatedId, String content) {
        try {
            Long currentId = SecurityUtils.getCurrentUserId();
            //默认未读
            Notification notification = new Notification(null, receiverId, content, "评论", relatedId, 0, new Date(), currentId);
            WebSocketSession session = webSocketSessionManager.getSession(receiverId);

            //存入数据库
            notificationMapper.insert(notification);

            //更新redis中的未读消息数
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + notification.getNotificationType() + ":" + receiverId;
            stringRedisTemplate.opsForValue().increment(unReadKey);
            stringRedisTemplate.expire(unReadKey, 1, TimeUnit.HOURS);
            //消息存入redis
            NotificationDTO notificationDTO1 = notificationMapper.selectCommentNotificationDTOById(targetTypeId, notification.getId());
            String unread = stringRedisTemplate.opsForValue().get(unReadKey);
            notificationDTO1.setUnreadCount(unread == null ? 0 : Integer.parseInt(unread));
            String notificatioKey = RedisCacheConstants.NOTIFICATION_MESSAGE + notification.getNotificationType() + ":" + notification.getUserId();
            String jsonStr = objectMapper.writeValueAsString(notificationDTO1);
            stringRedisTemplate.opsForZSet().add(notificatioKey, jsonStr, notification.getCreatedAt().getTime());
            //设置过期时间
            stringRedisTemplate.expire(notificatioKey, 7, TimeUnit.DAYS);

            //在线就发送
            if (session != null && session.isOpen()) {
                sendMessage(receiverId, notificationDTO1);
            } else {
                //处理离线消息
                handleOfflineMessage(notificationDTO1);
            }
        } catch (Exception e) {
            log.error("发送消息失败", e);
            throw new RuntimeException(e);
        }
    }

    //心理调查问卷通知
    @Override
    public void sendQuestionnaire(List<Long> receiverIds, Long relatedId, String content) {
        try {
            Long currentId = SecurityUtils.getCurrentUserId();
            for (Long receiverId : receiverIds) {
                //默认未读
                Notification notification = new Notification(null, receiverId, content, "问卷系统", relatedId, 0, new Date(), currentId);
                WebSocketSession session = webSocketSessionManager.getSession(receiverId);

                //存入数据库
                notificationMapper.insert(notification);

                //更新redis中的未读消息数
                String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + notification.getNotificationType() + ":" + receiverId;
                stringRedisTemplate.opsForValue().increment(unReadKey);
                stringRedisTemplate.expire(unReadKey, 1, TimeUnit.HOURS);
                //消息存入redis
                NotificationDTO notificationDTO1 = notificationMapper.selectQuestionNotificationDTOById(Long.valueOf(notification.getId()));
                String unread = stringRedisTemplate.opsForValue().get(unReadKey);
                notificationDTO1.setUnreadCount(unread == null ? 0 : Integer.parseInt(unread));
                String notificatioKey = RedisCacheConstants.NOTIFICATION_MESSAGE + notification.getNotificationType() + ":" + notification.getUserId();
                String jsonStr = objectMapper.writeValueAsString(notificationDTO1);
                stringRedisTemplate.opsForZSet().add(notificatioKey, jsonStr, notification.getCreatedAt().getTime());
                //设置过期时间
                stringRedisTemplate.expire(notificatioKey, 7, TimeUnit.DAYS);

                //在线就发送
                if (session != null && session.isOpen()) {
                    sendMessage(receiverId, notificationDTO1);
                } else {
                    //处理离线消息
                    handleOfflineMessage(notificationDTO1);
                }
            }
        } catch (Exception e) {
            log.error("发送消息失败", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendAnnouncement(Long announcementId, String content, List<Long> userIds) {
        try {
            Long currentId = SecurityUtils.getCurrentUserId();
            for (Long receiverId : userIds) {
                //默认未读
                Notification notification = new Notification(null, receiverId, content, "公告", announcementId, 0, new Date(), currentId);
                WebSocketSession session = webSocketSessionManager.getSession(receiverId);

                //存入数据库
                notificationMapper.insert(notification);

                //更新redis中的未读消息数
                String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + notification.getNotificationType() + ":" + receiverId;
                stringRedisTemplate.opsForValue().increment(unReadKey);
                stringRedisTemplate.expire(unReadKey, 1, TimeUnit.HOURS);
                //消息存入redis
                NotificationDTO notificationDTO1 = notificationMapper.selectAnnouncementNotificationDTOById(notification.getId());
                String unread = stringRedisTemplate.opsForValue().get(unReadKey);
                Integer unreadCount = Integer.parseInt(unread);
                notificationDTO1.setUnreadCount(unreadCount == null ? 0 : unreadCount);
                String notificatioKey = RedisCacheConstants.NOTIFICATION_MESSAGE + notification.getNotificationType() + ":" + notification.getUserId();
                String jsonStr = objectMapper.writeValueAsString(notificationDTO1);
                stringRedisTemplate.opsForZSet().add(notificatioKey, jsonStr, notification.getCreatedAt().getTime());
                //设置过期时间
                stringRedisTemplate.expire(notificatioKey, 7, TimeUnit.DAYS);

                //在线就发送
                if (session != null && session.isOpen()) {
                    sendMessage(receiverId, notificationDTO1);
                } else {
                    //处理离线消息
                    handleOfflineMessage(notificationDTO1);
                }
            }
        } catch (Exception e) {
            log.error("发送消息失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取点赞通知
     */
    @Override
    public Result getLikeNotification(Integer pageNum, Integer pageSize) {
        try {
            if (pageNum < 1) pageNum = 1;
            if (pageSize < 1) pageSize = 10;
            Long receiverId = SecurityUtils.getCurrentUserId();
            if (receiverId == null) {
                return Result.fail("请先登录");
            }

            //开始索引 结束索引
            Integer start = (pageNum - 1) * pageSize;
            Integer end = pageNum * pageSize - 1;
            List<NotificationDTO> likenotification = new ArrayList<>();

            //把未读消息设置成已读
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + "点赞" + ":" + receiverId;
            stringRedisTemplate.opsForValue().set(unReadKey, "0");
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("id")
                    .eq("user_id", receiverId)
                    .eq("notification_type", "点赞")
                    .eq("is_read", 0);
            List<Long> ids = notificationMapper.selectList(queryWrapper)
                    .stream()
                    .map(Notification::getId)
                    .collect(Collectors.toList());
            if (!ids.isEmpty()) {
                notificationMapper.batchUpdateIsRead(ids);
            }

            //从redis中获取通知
            String notificationKey = RedisCacheConstants.NOTIFICATION_MESSAGE + "点赞" + ":" + receiverId;
            Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(notificationKey, start, end);
            if (typedTuples != null && !typedTuples.isEmpty()) {
                for (ZSetOperations.TypedTuple<String> tuples : typedTuples) {
                    String oldJson = tuples.getValue();
                    Double score = tuples.getScore();
                    NotificationDTO notificationDTO = objectMapper.readValue(oldJson, NotificationDTO.class);
                    notificationDTO.setUnreadCount(0);
                    String newJson = objectMapper.writeValueAsString(notificationDTO);
                    stringRedisTemplate.opsForZSet().remove(notificationKey, oldJson);
                    stringRedisTemplate.opsForZSet().add(notificationKey, newJson, score);
                    likenotification.add(notificationDTO);
                }

                //计算总条数
                Long total = stringRedisTemplate.opsForZSet().zCard(notificationKey);
                total = total == null ? 0 : total;
                //总页数
                long totalPage = (total + pageSize - 1) / pageSize;

                return Result.ok(new PageDTO<>(likenotification, total, totalPage));
            }

            //redis未命中就从数据库里面查询
            if (likenotification == null || likenotification.isEmpty()) {
                List<NotificationDTO> notificationDTOS = notificationMapper.selectLikeNotificationDto(receiverId, start, pageSize);
                //总条数
                Long total = notificationMapper.countNotification(receiverId, "点赞");
                //总页数
                Long totalPage = (total + pageSize - 1) / pageSize;
                PageDTO<NotificationDTO> pageDTO = new PageDTO<>();
                pageDTO.setRows(notificationDTOS)    // 当前页数据
                        .setTotal(total)              // 总条数
                        .setTotalPage(totalPage);     // 总页数
                //消息存入redis
                if (notificationDTOS != null) {
                    for (NotificationDTO notificationDTO : notificationDTOS) {
                        double score = notificationDTO.getCreatedAt().getTime();
                        notificationDTO.setUnreadCount(0);
                        String s = objectMapper.writeValueAsString(notificationDTO);
                        stringRedisTemplate.opsForZSet().add(notificationKey, s, score);

                    }
                    //设置过期时间
                    stringRedisTemplate.expire(notificationKey, 7, TimeUnit.DAYS);
                }

                return Result.ok(pageDTO);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException("获取通知消息失败" + e);
        }
        return Result.fail("获取消息失败");
    }


    @Override
    public Result getCommentNotification(Integer pageNum, Integer pageSize) {
        try {
            if (pageNum < 1) pageNum = 1;
            if (pageSize < 1) pageSize = 10;
            Long receiverId = SecurityUtils.getCurrentUserId();
            if (receiverId == null) {
                return Result.fail("请先登录");
            }

            //开始索引 结束索引
            Integer start = (pageNum - 1) * pageSize;
            Integer end = pageNum * pageSize - 1;
            List<NotificationDTO> Commentnotification = new ArrayList<>();

            //把未读消息设置成已读
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + "评论" + ":" + receiverId;
            stringRedisTemplate.opsForValue().set(unReadKey, "0");
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("id")
                    .eq("user_id", receiverId)
                    .eq("notification_type", "评论")
                    .eq("is_read", 0);
            List<Long> ids = notificationMapper.selectList(queryWrapper)
                    .stream()
                    .map(Notification::getId)
                    .collect(Collectors.toList());
            if (!ids.isEmpty()) {
                notificationMapper.batchUpdateIsRead(ids);
            }

            //从redis中获取通知
            String notificationKey = RedisCacheConstants.NOTIFICATION_MESSAGE + "评论" + ":" + receiverId;
            Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(notificationKey, start, end);
            if (typedTuples != null && !typedTuples.isEmpty()) {
                for (ZSetOperations.TypedTuple<String> tuples : typedTuples) {
                    //获取对应的json
                    String oldJson = tuples.getValue();
                    Double score = tuples.getScore();
                    NotificationDTO notificationDTO = objectMapper.readValue(oldJson, NotificationDTO.class);
                    notificationDTO.setUnreadCount(0);
                    String newJson =  objectMapper.writeValueAsString(notificationDTO);
                    stringRedisTemplate.opsForZSet().remove(notificationKey, oldJson);
                    stringRedisTemplate.opsForZSet().add(notificationKey, newJson, score);
                    Commentnotification.add(notificationDTO);
                }

                //计算总条数
                Long total = stringRedisTemplate.opsForZSet().zCard(notificationKey);
                total = total == null ? 0 : total;
                //总页数
                long totalPage = (total + pageSize - 1) / pageSize;

                return Result.ok(new PageDTO<>(Commentnotification, total, totalPage));
            }

            //redis未命中就从数据库里面查询
            if (Commentnotification == null || Commentnotification.isEmpty()) {
                List<NotificationDTO> notificationDTOS = notificationMapper.selectCommentNotificationDto(receiverId, start, pageSize);
                System.out.println(notificationDTOS);
                //总条数
                Long total = notificationMapper.countNotification(receiverId, "评论");
                //总页数
                Long totalPage = (total + pageSize - 1) / pageSize;
                PageDTO<NotificationDTO> pageDTO = new PageDTO<>();
                pageDTO.setRows(notificationDTOS)    // 当前页数据
                        .setTotal(total)              // 总条数
                        .setTotalPage(totalPage);     // 总页数

                //消息存入redis
                if (notificationDTOS != null) {
                    for (NotificationDTO notificationDTO : notificationDTOS) {
                        double score = notificationDTO.getCreatedAt().getTime();
                        notificationDTO.setUnreadCount(0);
                        String s = objectMapper.writeValueAsString(notificationDTO);
                        stringRedisTemplate.opsForZSet().add(notificationKey, s, score);
                    }
                    //设置过期时间
                    stringRedisTemplate.expire(notificationKey, 7, TimeUnit.DAYS);
                }

                return Result.ok(pageDTO);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException("获取通知消息失败" + e);
        }
        return Result.fail("获取消息失败");
    }

    @Override
    public Result getMarkNotification(Integer pageNum, Integer pageSize) {
        try {
            if (pageNum < 1) pageNum = 1;
            if (pageSize < 1) pageSize = 10;
            Long receiverId = SecurityUtils.getCurrentUserId();
            if (receiverId == null) {
                return Result.fail("请先登录");
            }

            //开始索引 结束索引
            Integer start = (pageNum - 1) * pageSize;
            Integer end = pageNum * pageSize - 1;
            List<NotificationDTO> marknotification = new ArrayList<>();

            //把未读消息设置成已读
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + "收藏" + ":" + receiverId;
            stringRedisTemplate.opsForValue().set(unReadKey, "0");
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("id")
                    .eq("user_id", receiverId)
                    .eq("notification_type", "收藏")
                    .eq("is_read", 0);
            List<Long> ids = notificationMapper.selectList(queryWrapper)
                    .stream()
                    .map(Notification::getId)
                    .collect(Collectors.toList());
            if (!ids.isEmpty()) {
                notificationMapper.batchUpdateIsRead(ids);
            }

            //从redis中获取通知
            String notificationKey = RedisCacheConstants.NOTIFICATION_MESSAGE + "收藏" + ":" + receiverId;
            Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(notificationKey, start, end);
            if (typedTuples != null && !typedTuples.isEmpty()) {
                for (ZSetOperations.TypedTuple<String> tuples : typedTuples) {
                    //获取对应的json
                    String oldJson = tuples.getValue();
                    Double score = tuples.getScore();
                    NotificationDTO notificationDTO = objectMapper.readValue(oldJson, NotificationDTO.class);
                    notificationDTO.setUnreadCount(0);
                    String newJson =  objectMapper.writeValueAsString(notificationDTO);
                    stringRedisTemplate.opsForZSet().remove(notificationKey, oldJson);
                    stringRedisTemplate.opsForZSet().add(notificationKey, newJson, score);
                    marknotification.add(notificationDTO);
                }

                //计算总条数
                Long total = stringRedisTemplate.opsForZSet().zCard(notificationKey);
                total = total == null ? 0 : total;
                //总页数
                long totalPage = (total + pageSize - 1) / pageSize;

                return Result.ok(new PageDTO<>(marknotification, total, totalPage));
            }

            //redis未命中就从数据库里面查询
            if (marknotification == null || marknotification.isEmpty()) {
                List<NotificationDTO> notificationDTOS = notificationMapper.selectMarkNotificationDto(receiverId, start, pageSize);
                //总条数
                Long total = notificationMapper.countNotification(receiverId, "收藏");
                //总页数
                Long totalPage = (total + pageSize - 1) / pageSize;
                PageDTO<NotificationDTO> pageDTO = new PageDTO<>();
                pageDTO.setRows(notificationDTOS)    // 当前页数据
                        .setTotal(total)              // 总条数
                        .setTotalPage(totalPage);     // 总页数

                //消息存入redis
                if (notificationDTOS != null) {
                    for (NotificationDTO notificationDTO : notificationDTOS) {
                        double score = notificationDTO.getCreatedAt().getTime();
                        notificationDTO.setUnreadCount(0);
                        String s = objectMapper.writeValueAsString(notificationDTO);
                        stringRedisTemplate.opsForZSet().add(notificationKey, s, score);
                    }
                    //设置过期时间
                    stringRedisTemplate.expire(notificationKey, 7, TimeUnit.DAYS);
                }

                return Result.ok(pageDTO);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException("获取通知消息失败" + e);
        }
        return Result.fail("获取消息失败");
    }

    //获取调查问卷通知
    @Override
    public Result getQuestionNotification(Integer pageNum, Integer pageSize) {
        try {
            if (pageNum < 1) pageNum = 1;
            if (pageSize < 1) pageSize = 10;
            Long receiverId = SecurityUtils.getCurrentUserId();
            if (receiverId == null) {
                return Result.fail("请先登录");
            }

            //开始索引 结束索引
            Integer start = (pageNum - 1) * pageSize;
            Integer end = pageNum * pageSize - 1;
            List<NotificationDTO> questionnotification = new ArrayList<>();

            //把未读消息设置成已读
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + "问卷系统" + ":" + receiverId;
            stringRedisTemplate.opsForValue().set(unReadKey, "0");
            QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("id")
                    .eq("user_id", receiverId)
                    .eq("notification_type", "问卷系统")
                    .eq("is_read", 0);
            List<Long> ids = notificationMapper.selectList(queryWrapper)
                    .stream()
                    .map(Notification::getId)
                    .collect(Collectors.toList());
            if (!ids.isEmpty()) {
                notificationMapper.batchUpdateIsRead(ids);
            }

            //从redis中获取通知
            String notificationKey = RedisCacheConstants.NOTIFICATION_MESSAGE + "问卷系统" + ":" + receiverId;
            Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(notificationKey, start, end);
            if (typedTuples != null && !typedTuples.isEmpty()) {
                for (ZSetOperations.TypedTuple<String> tuples : typedTuples) {
                    //获取对应的json
                    String oldJson = tuples.getValue();
                    Double score = tuples.getScore();
                    NotificationDTO notificationDTO = objectMapper.readValue(oldJson, NotificationDTO.class);
                    notificationDTO.setUnreadCount(0);
                    String newJson =  objectMapper.writeValueAsString(notificationDTO);
                    stringRedisTemplate.opsForZSet().remove(notificationKey, oldJson);
                    stringRedisTemplate.opsForZSet().add(notificationKey, newJson, score);
                    questionnotification.add(notificationDTO);
                }

                //计算总条数
                Long total = stringRedisTemplate.opsForZSet().zCard(notificationKey);
                total = total == null ? 0 : total;
                //总页数
                long totalPage = (total + pageSize - 1) / pageSize;

                return Result.ok(new PageDTO<>(questionnotification, total, totalPage));
            }

            //redis未命中就从数据库里面查询
            if (questionnotification == null || questionnotification.isEmpty()) {
                List<NotificationDTO> notificationDTOS = notificationMapper.selectQuestionNotificationDto(receiverId, start, pageSize);
                //总条数
                Long total = notificationMapper.countNotification(receiverId, "问卷系统");
                //总页数
                Long totalPage = (total + pageSize - 1) / pageSize;
                PageDTO<NotificationDTO> pageDTO = new PageDTO<>();
                pageDTO.setRows(notificationDTOS)    // 当前页数据
                        .setTotal(total)              // 总条数
                        .setTotalPage(totalPage);     // 总页数

                //消息存入redis
                if (notificationDTOS != null) {
                    for (NotificationDTO notificationDTO : notificationDTOS) {
                        double score = notificationDTO.getCreatedAt().getTime();
                        notificationDTO.setUnreadCount(0);
                        String s = objectMapper.writeValueAsString(notificationDTO);
                        stringRedisTemplate.opsForZSet().add(notificationKey, s, score);
                    }
                    //设置过期时间
                    stringRedisTemplate.expire(notificationKey, 7, TimeUnit.DAYS);
                }

                return Result.ok(pageDTO);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException("获取通知消息失败" + e);
        }
        return Result.fail("获取消息失败");
    }

    @Override
    public Result getUnreadCountByType(String notificationType) {
        Long userId = SecurityUtils.getCurrentUserId();

        //从redis中查询
        String unreadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + notificationType + ":" + userId;
        String s = stringRedisTemplate.opsForValue().get(unreadKey);
        Integer unreadCount = null;
        if (s != null && !s.trim().isEmpty()) {
            unreadCount = Integer.parseInt(s);
        }
        //如果redis未命中，从数据库里面查询
        if (unreadCount == null) {
            unreadCount = notificationMapper.selectCounts(notificationType, userId);
            //存入redis
            if (unreadCount != null) {
                String unread = String.valueOf(unreadCount);
                stringRedisTemplate.opsForValue().set(unreadKey, unread);
                stringRedisTemplate.expire(unreadKey, 1, TimeUnit.HOURS);
            }
        }
        return Result.ok(unreadCount != null ? unreadCount : 0);
    }

    @Override
    public Result delectNoticication(String notificationId1) {
        if (notificationId1 == null) {
            return Result.fail("消息Id不能为空");
        }
        Long notificaitionId = Long.valueOf(notificationId1);
        Notification notification = notificationMapper.selectById(notificaitionId);
        if (notification == null) {
            return Result.fail("数据已被删除");
        }
        Long currentId=SecurityUtils.getCurrentUserId();
        String type = notificationMapper.notificationType(notificaitionId);
        NotificationDTO notificationDTO = null;
        if ("点赞".equals(type)) {
            notificationDTO = notificationMapper.selectLikeNotificationDtoById(notificaitionId);
        } else if ("收藏".equals(type)) {
            notificationDTO = notificationMapper.selectMarkNotificationDTOById(notificaitionId);
        } else if ("问卷系统".equals(type)) {
            notificationDTO = notificationMapper.selectQuestionNotificationDTOById(notificaitionId);
        } else {
            Integer targetType = notificationMapper.targetId(notificaitionId);
            if (targetType != null) {
                notificationDTO = notificationMapper.selectCommentNotificationDTOById(targetType, notificaitionId);
            }
        }
        if (notificationDTO != null) {
            String unReadKey = RedisCacheConstants.NOTIFICATION_UNREAD_PREFIX + notificationDTO.getType() + ":" + currentId;
            String unread = stringRedisTemplate.opsForValue().get(unReadKey);
            notificationDTO.setUnreadCount(unread == null ? 0 : Integer.parseInt(unread));
            String jsonStr = null;
            try {
                jsonStr = objectMapper.writeValueAsString(notificationDTO);
            } catch (JsonProcessingException e) {
                log.error("删除失败，序列化失败");
                throw new RuntimeException(e);

            }
            log.info(jsonStr);
            String key = RedisCacheConstants.NOTIFICATION_MESSAGE + type + ":" + currentId;
            stringRedisTemplate.opsForZSet().remove(key, jsonStr);
        }
        //从数据库删除
        notificationMapper.deleteNotification(notificaitionId);
        return Result.ok("消息删除成功");
    }

    /**
     * 处理离线消息，接收者离线时存储到redis
     */
    public void handleOfflineMessage(NotificationDTO message) {
        //存储离线消息
        try {
            String s = objectMapper.writeValueAsString(message);
            String offlineKey = RedisCacheConstants.NOTIFICATION_OFFLINE_PREFIX + message.getType() + ":" + message.getReceiverId();
            stringRedisTemplate.opsForZSet().add(offlineKey, s, message.getCreatedAt().getTime());
        } catch (Exception e) {
            throw new RuntimeException("消息存入redis失败");

        }
    }

}



